package _11_整理题目._6_模拟设计._设计新的数据结构;

import org.junit.Test;

import java.util.*;

/**
 * https://leetcode-cn.com/problems/insert-delete-getrandom-o1/description/
 * 设计一个支持在平均时间复杂度 O(1) 下，执行以下操作的数据结构。
 *      1、insert(val)：当元素 val 不存在时，向集合中插入该项。
 *      2、remove(val)：元素 val 存在时，从集合中移除该项。
 *      3、getRandom：随机返回现有集合中的一项。每个元素应该有相同的概率被返回。
 *
 * 思路：
 *      使用数组 ArrayList 可以实现 随机访问，直接随机一个下标直接返回
 *      插入 可以直接插入数组后面，也是 o1
 *      删除某个元素 需要先找到位置，然后与最后一个元素交换再删除就可以 o1 了
 *          所以需要 o1 时间找到 元素下标，使用 HashMap 存储 "元素值，下标"
 *
 */
public class _03_O1时间插入删除和获取随机元素 {
    private Map<Integer, Integer> map;
    private List<Integer> list;
    private Random random;

    /** Initialize your data structure here. */
    public _03_O1时间插入删除和获取随机元素() {
        map = new HashMap<>();
        list = new ArrayList<>();
        random = new Random();
    }

    /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
    public boolean insert(int val) {
        if(map.containsKey(val)) return false;

        map.put(val, list.size());
        list.add(val);
        return true;
    }

    /** Removes a value from the set. Returns true if the set contained the specified element. */
    public boolean remove(int val) {
        if(!map.containsKey(val)) return false;

        int lastValue = list.get(list.size()-1);
        int index = map.get(val);
        list.set(index, lastValue);
        map.put(lastValue, index);

        list.remove(list.size()-1);
        map.remove(val);
        return true;
    }

    /** Get a random element from the set. */
    public int getRandom() {
        return list.get(random.nextInt(list.size()));
    }

    @Test
    public void main() {
        // 初始化一个空的集合。
        _03_O1时间插入删除和获取随机元素 randomSet = new _03_O1时间插入删除和获取随机元素();
        // 向集合中插入 1 。返回 true 表示 1 被成功地插入。
        randomSet.insert(1);
        // 返回 false ，表示集合中不存在 2 。
        randomSet.remove(2);
        // 向集合中插入 2 。返回 true 。集合现在包含 [1,2] 。
        randomSet.insert(2);
        // getRandom 应随机返回 1 或 2 。
        randomSet.getRandom();
        // 从集合中移除 1 ，返回 true 。集合现在包含 [2] 。
        randomSet.remove(1);
        // 2 已在集合中，所以返回 false 。
        randomSet.insert(2);
        // 由于 2 是集合中唯一的数字，getRandom 总是返回 2 。
        randomSet.getRandom();

    }

}
